/******************************************************************************
 * Copyright (C) 2015  671643387@qq.com
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 *
 *****************************************************************************/

#ifndef UGAME_EXCEPTION_H_
#define UGAME_EXCEPTION_H_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <exception>
#include <string>

namespace UGame {

    /* Exception */
    class Exception: public std::exception
    {
    public:
        Exception(void);
        explicit Exception(int _Code);
        Exception(const std::string& _Message, int _Code = -1);
        ~Exception(void) throw ();

        int code(void) const { return _code; }
        const char* what(void) const throw () { return _message.c_str(); }

    private:
        int _code;
        std::string _message;
    };

    ///////////////////////////////////////////////////////////////////////////
#define DECLARE_EXCEPTION_CODE(CLS, BASE, CODE)                          \
    class CLS : public BASE                                              \
    {                                                                    \
    public:                                                              \
        CLS(int _Code = CODE);                                           \
        CLS(const std::string& _Message, int _Code = CODE);              \
        ~CLS(void) throw ();                                             \
        CLS& operator = (const CLS& exc);                                \
        const char* name(void) const;                                    \
    };

#define DECLARE_EXCEPTION(CLS, BASE)                                     \
    DECLARE_EXCEPTION_CODE(CLS, BASE, -1)

#define IMPLEMENT_EXCEPTION(CLS, BASE, NAME)                             \
    CLS::CLS(int _Code) : BASE(_Code)                                    \
    {                                                                    \
    }                                                                    \
    CLS::CLS(const std::string& _Message, int _Code)                     \
        : BASE(_Message, _Code)                                          \
    {                                                                    \
    }                                                                    \
    CLS::~CLS(void) throw ()                                             \
    {                                                                    \
    }                                                                    \
    CLS& CLS::operator = (const CLS& exc)                                \
    {                                                                    \
        BASE::operator = (exc);                                          \
        return *this;                                                    \
    }                                                                    \
    const char* CLS::name(void) const                                    \
    {                                                                    \
        return NAME;                                                     \
    }                                                                    \


    /* Logic exceptions */
    DECLARE_EXCEPTION(LogicException, Exception)
    DECLARE_EXCEPTION(AssertionViolationException, LogicException)
    DECLARE_EXCEPTION(NullPointerException, LogicException)
    DECLARE_EXCEPTION(NullValueException, LogicException)
    DECLARE_EXCEPTION(BugcheckException, LogicException)
    DECLARE_EXCEPTION(InvalidArgumentException, LogicException)
    DECLARE_EXCEPTION(NotImplementedException, LogicException)
    DECLARE_EXCEPTION(RangeException, LogicException)
    DECLARE_EXCEPTION(IllegalStateException, LogicException)
    DECLARE_EXCEPTION(InvalidAccessException, LogicException)
    DECLARE_EXCEPTION(SignalException, LogicException)
    DECLARE_EXCEPTION(UnhandledException, LogicException)

    /* Runtime exceptions */
    DECLARE_EXCEPTION(RuntimeException, Exception)
    DECLARE_EXCEPTION(NotFoundException, RuntimeException)
    DECLARE_EXCEPTION(ExistsException, RuntimeException)
    DECLARE_EXCEPTION(TimeoutException, RuntimeException)
    DECLARE_EXCEPTION(SystemException, RuntimeException)
}

#endif // UGAME_EXCEPTION_H_
